﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Logic.ClarizenSvc;
using Logic.ClarizenObjects;
using System.Reflection;
using Logic.Models;

namespace Logic.ClarizenObjects
{
    public class BaseObject
    {
        [Clarizen]
        public EntityId ID { get; set; }
        public BaseObject(GenericEntity entity)
        {
            this.Load(entity);
        }

        private void VerifyID()
        {
            if (this.ID == null)
                this.ID = new EntityId();
            if (string.IsNullOrEmpty(this.ID.TypeName))
                this.ID.TypeName = this.GetType().Name;
        }

        public static T Intitialize<T>(GenericEntity entity) where T : BaseObject, new()
        {
            if (entity == null)
                return null;
            
            T obj = new T();
            obj.Load(entity);

            return obj;
        }

        private void Load(GenericEntity entity)
        {
            if (entity == null)
                return;

            this.ID = entity.Id;
            VerifyID();

            if (entity.Values != null)
                foreach (var item in entity.Values)
                {
                    var propName = item.FieldName.Replace(".", "_");
                    var property = this.GetType().GetProperty(propName);
                    if (property != null)
                        property.SetValue(this, item.Value, null);
                }

            this.Update = this.Delete = true;
            if (entity.Permissions != null)
            {
                if(entity.Permissions.FieldPermissions != null)
                {
                    this.Permissions = new Dictionary<string, Boolean>();
                    foreach (var p in entity.Permissions.FieldPermissions)
                        this.Permissions.Add(p.FieldName, p.Permissions == FieldPermissions.Read ? false : true);
                }
                if(entity.Permissions.ObjectPermissions != null)
                {
                    this.Update = entity.Permissions.ObjectPermissions.Contains(ObjectPermissions.Update);
                    this.Delete = entity.Permissions.ObjectPermissions.Contains(ObjectPermissions.Delete);
                }

            }

            
        }

        public BaseObject()
        {
            VerifyID();
        }

        // is not sent or retrieved
        [Clarizen]
        public List<CustomField> CustomFields { get; set; }

        [Clarizen]
        public Dictionary<String,Boolean> Permissions { get; set; }

        [Clarizen]
        public Boolean Update { get; set; }
        [Clarizen]
        public Boolean Delete { get; set; }

        public GenericEntity ToGenericEntity()
        {
            GenericEntity entity = new GenericEntity { Id = this.ID };
            if (entity.Id == null)
                entity.Id = new EntityId { TypeName = this.GetType().Name };

            List<FieldValue> fields = new List<FieldValue>();

            foreach (var prop in this.GetEditProperties())
            {
                var value = prop.GetValue(this, null);

                if (value is Duration && value != null && ((Duration)value).Value == 0)
                    continue;

                if (value != null && !(value is GenericEntity && string.IsNullOrEmpty(((GenericEntity)value).Id.Value)))
                    fields.Add(new FieldValue { FieldName = prop.Name.Replace("_", "."), Value = value });
            }
            if (CustomFields != null)
                fields.AddRange(CustomFields.Select(cf => cf.ToFieldValue()));
            entity.Values = fields.ToArray();
            return entity;
        }

        public static String[] GetFields(Type t)
        {
            return t.GetProperties().Where(p =>
            {
                var attr = p.GetCustomAttributes(typeof(ClarizenAttribute), false);
                return attr.Length == 0 || ((ClarizenAttribute)attr[0]).Selectable;
            }).Select(p => p.Name.Replace("_", ".")).ToArray();
        }

        public static String[] GetFields<T>()
        {
            return typeof(T).GetProperties().Where(p =>
            {
                var attr = p.GetCustomAttributes(typeof(ClarizenAttribute), false);
                return attr.Length == 0 || ((ClarizenAttribute)attr[0]).Selectable;
            }).Select(p => p.Name.Replace("_", ".")).ToArray();
        }

        public IEnumerable<PropertyInfo> GetEditProperties()
        {
            return this.GetType().GetProperties().Where(p =>
            {
                var attr = p.GetCustomAttributes(typeof(ClarizenAttribute), false);
                return attr.Length == 0 || ((ClarizenAttribute)attr[0]).Editable;
            });
        }
    }
}
